package sunwul.mall.commoncore.config;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import sunwul.mall.commonbase.constant.BusinessStatusEnum;
import sunwul.mall.commonbase.constant.HttpConstants;
import sunwul.mall.commonbase.model.Result;
import sunwul.mall.commoncore.ResourceConstant;
import sunwul.mall.commoncore.filter.TokenTranslationFilter;

import java.io.PrintWriter;

/**
 * @author sunwul
 * @date 2024/12/27 16:45
 * @description Spring Security安全框架的资源服务器配置
 */
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true) // 调用前验证
public class ResourceServerConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private TokenTranslationFilter tokenTranslationFilter;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // 关闭跨站伪造
        http.cors().disable();
        // 关闭跨域请求
        http.csrf().disable();
        // 关闭session使用策略
        http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);

        // token解析器, 将token转换为Security安全框架能够认识的用户信息, 再存放到当前资源服务器的容器中
        http.addFilterBefore(tokenTranslationFilter,
                UsernamePasswordAuthenticationFilter.class); // 在用户名密码认证之前处理

        // 配置异常处理
        http.exceptionHandling()
                .authenticationEntryPoint(authenticationEntryPoint()) // 处理未携带token的请求
                .accessDeniedHandler(accessDeniedHandler()); // 处理携带token, 但权限不足的请求

        // 控制请求是否需要进行认证
        http.authorizeHttpRequests()
                .antMatchers(ResourceConstant.RESOURCE_ALLOW_URLS)
                .permitAll()
                .anyRequest().authenticated(); // 除了需要放行的请求, 都需要进行身份认证

    }

    /**
     * 处理未携带token的请求
     */
    @Bean
    public AuthenticationEntryPoint authenticationEntryPoint() {
        return (request, response, authException) -> {
            response.setContentType(HttpConstants.APPLICATION_JSON);
            response.setCharacterEncoding(HttpConstants.UTF_8);

            Result<Object> result = Result.fail(BusinessStatusEnum.UN_AUTHORIZATION);
            String s = new ObjectMapper().writeValueAsString(result);
            PrintWriter writer = response.getWriter();
            writer.write(s);
            writer.flush();
            writer.close();
        };
    }

    /**
     * 处理携带token但权限不足的请求
     */
    @Bean
    public AccessDeniedHandler accessDeniedHandler() {
        return (request, response, accessDeniedException) -> {
            response.setContentType(HttpConstants.APPLICATION_JSON);
            response.setCharacterEncoding(HttpConstants.UTF_8);

            Result<Object> result = Result.fail(BusinessStatusEnum.ACCESS_DENY_FAIL);
            String s = new ObjectMapper().writeValueAsString(result);
            PrintWriter writer = response.getWriter();
            writer.write(s);
            writer.flush();
            writer.close();
        };
    }
}
